
mb.async = {
  responder : function(callback) {
    if (typeof (callback) == 'function') {
      return { onSuccess : callback, onFailure : callback };
    } else if (callback.onSuccess && typeof (callback.onSuccess) == 'function' &&
               callback.onFailure && typeof (callback.onFailure) == 'function') {
      return callback;
    } else {
      throw 'Given callback object is not function or responder';
    }
  }
  ,
  map : function(arr, func, callback) {
    callback = mb.async.responder(callback);
    var next = callback.onSuccess;
    var count = arr.length;
    var rarr = new Array(arr.length);
    if (count==0) callback.onSuccess(rarr);
    jQuery.each(arr, function(i, a) {
      func.call(null, a, i, arr, {
        onSuccess : function(ret) {
          rarr[i] = ret;
          count--;
          if (count==0) next(rarr);
        },
        onFailure : function(error) {
          rarr[i] = error;
          count--;
          next = callback.onFailure;
          if (count==0) next(rarr);
        }
      })
    })
  }
  ,
  iterate : function(arr, func, callback) {
    callback = mb.async.responder(callback);
    var error = false;
    var rarr = new Array(arr.length);

    _iterate(0);

    function _iterate(i) {
      if (i<arr.length) {
        func.call(null, arr[i], i, arr, {
          onSuccess : function(ret) {
            rarr[i] = ret;
            _iterate(i+1);
          },
          onFailure : function(error) {
            rarr[i] = error;
            error = true;
            _iterate(i+1);
          }
        });
      } else {
        (error ? callback.onFailure : callback.onSuccess)(rarr);
      }
    }

  }
  ,
  sync : function(funcs, callback) {
    callback = aforus.lang.responder(callback);

    function exec(context, i, funcs) {
      if (i>=funcs.length) {
        callback.onSuccess(context);
        return;
      }
      var func = funcs[i]; 
      var label = func.toString().match(/^function\s+([^\(]*)/) ? 
                  RegExp.$1 :
                  '_func'+i;
      func.call(thisObj, context, {
        onSuccess : function(result) {
          context[label] = result;
          exec(context, i+1, funcs);
        },
        onFailure : function(error) {
          context[label] = error;
          callback.onFailure(context);
        }
      })
    }
    exec({}, 0, funcs);
  }
};
